﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.CodeDom.Compiler;
using System.Collections.ObjectModel;

namespace mcws.httpd.Cryostasis
{
    public class Engine<T>
    {
        private Collection<Script> _Modules = new Collection<Script>();
        public Collection<Script> Modules { get { return _Modules; } }
        public Script LoadModule(string file,params string[] sdkfiles)
        {
            T _t = default(T);
            var f = typeof(T);
            if (f.BaseType == typeof(Script) == false)
            {
                throw new Exception("You object must inherit from Script!");
            }
            FileInfo fi = new FileInfo(file);
            Console.WriteLine("Loading and compiling " + fi.Name);
            //Finds the correct compiler based off of the file extension.
            CodeDomProvider cdp = CodeDomProvider.CreateProvider(CodeDomProvider.GetLanguageFromExtension(fi.Extension));
            CompilerParameters cp = new CompilerParameters();
            cp.GenerateInMemory = true; //Sets it to be loaded into memory.
            string dll = this.GetType().Assembly.CodeBase.Replace("file:///","");
            cp.ReferencedAssemblies.Add(dll); //Adds this .dll to the compilation.
            cp.ReferencedAssemblies.AddRange(sdkfiles); //Adds specified dlls to the compilation.
            cp.ReferencedAssemblies.Add("System.dll");//Adds required .NET stuff.
            cp.ReferencedAssemblies.Add("System.Xml.dll");
            cp.ReferencedAssemblies.Add("System.Data.dll");
            CompilerResults cr = cdp.CompileAssemblyFromFile(cp, file); //Compiles it.
            if (cr.Errors.Count > 0)
            {
                //Reports compilation errors.
                StringBuilder sb = new StringBuilder();
                foreach (CompilerError ce in cr.Errors)
                {
                    sb.AppendLine("Error:" + ce.ErrorText + " | " + ce.Line + "," + ce.Column);
                }
                throw new Exception("Error compiling: " + sb.ToString());
            }
            else
            {
                //Load it.
                foreach (Type t in cr.CompiledAssembly.GetTypes())
                {
                    try
                    {
                        object tp = Activator.CreateInstance(t);
                        //If its a script, load it.
                        if (tp is Script)
                        {
                            Modules.Add((Script)tp);
                            Modules[Modules.Count - 1].FileName = fi.Name;
                            Modules[Modules.Count - 1].CompiledAssembly = cr.CompiledAssembly;
                            Console.WriteLine("Loading of " + fi.Name + " completed!");
                            return Modules[Modules.Count - 1];
                        }
                    }
                    catch (Exception)
                    {
                    }
                }               
            }
            throw new Exception();
        }
        public void UnloadModule(Script scrp)
        {
            foreach (Script mod in _Modules)
            {
                if (mod == scrp)
                {
                    _Modules.Remove(scrp);
                    break;
                }
            }
            GC.Collect();
        }
    }
}
